.text
.section .rodata
.align 8
.LC0:
	.string	"%d\t"
.LC1:
	.string	"arr[%d][%zu][%zu] = %d \t"

.text
.globl main
.type main, @function
main:
    pushq %rbp
    movq %rsp, %rbp

    // sizeof(arr) = 2 * 3 * 4 * 4 = 96
    // sizeof(*p) = 8
    // sizeof(i) + sizeof(j) + sizeof(k) = 12
    // 总共116，距离16的倍数最近的是128
    subq $128, %rsp

    // 以下代码是考过来的，自己去写没必要，但是也能看出来内存布局，不管几维数组，都是一个个元素挨着放的，最终都是一维数组，这样理解就轻松多了
    movl	$1, -112(%rbp)
	movl	$2, -108(%rbp)
	movl	$3, -104(%rbp)
	movl	$4, -100(%rbp)
	movl	$5, -96(%rbp)
	movl	$6, -92(%rbp)
	movl	$7, -88(%rbp)
	movl	$8, -84(%rbp)
	movl	$9, -80(%rbp)
	movl	$10, -76(%rbp)
	movl	$11, -72(%rbp)
	movl	$12, -68(%rbp)
	movl	$11, -64(%rbp)
	movl	$12, -60(%rbp)
	movl	$13, -56(%rbp)
	movl	$14, -52(%rbp)
	movl	$15, -48(%rbp)
	movl	$16, -44(%rbp)
	movl	$17, -40(%rbp)
	movl	$18, -36(%rbp)
	movl	$19, -32(%rbp)
	movl	$110, -28(%rbp)
	movl	$111, -24(%rbp)
	movl	$112, -20(%rbp)

    // 接下来对内存做划分
    // arr：-112(%rbp)
    // p: -16(%rbp)
    // i: -8(%rbp)
    // j: -4(%rbp)
    // k: -116(%rbp)
    // -128 ~ -116留空
    leaq -112(%rbp) /* arr */, %rax
    movq %rax, -16(%rbp) /* p */
    movl $0, -8(%rbp) /* i */
    jmp .FOR_COMPARE
.FOR_ENTER:
    cmpl $0, -8(%rbp) /* i */
    jle .FOR_PRINTF
    movl -8(%rbp) /* i */, %eax
    andl $3, %eax
    testl %eax, %eax
    jne .FOR_PRINTF
.FOR_PUTCHAR:
    movq $10, %rdi
    call putchar
.FOR_PRINTF:
    movq -16(%rbp) /* p */, %rdx
    movl -8(%rbp) /* i */, %eax
    cltq
    movl (%rdx, %rax, 4), %esi
    leaq .LC0(%rip), %rdi
    movl $0, %eax
    call printf
    incl -8(%rbp) /* i */
.FOR_COMPARE:
    movl -8(%rbp) /* i */, %eax
    cmpl $24, %eax
    jl .FOR_ENTER

.FOR_COMPLETE:
    movq $10, %rdi
    call putchar

    movl $0, -8(%rbp) /* i */
    jmp .FOR_2_OUT_COMPARE
    // 第二个for的主体
.FOR_2_OUT_ENTER:
    movl $0, -4(%rbp) /* j */
    jmp .FOR_2_MID_COMPARE
.FOR_2_MID_ENTER:
    movl $0, -116(%rbp) /* k */
    jmp .FOR_2_INNER_COMPARE
.FOR_2_INNER_ENTER:
    // 这里我算是看明白了，这里计算索引的公式是((3 * i + j) * 4 + k)
    // 再通用一点呢，就是((二维长度*i + j) * 三维长度 + k)
    // 这里稍微用了一点点技巧，把*3换成了i * 2 + i,把乘法变成了加法
    movl -8(%rbp) /* i */, %eax
    movslq %eax, %rdx
    movq %rdx, %rax
    salq $1, %rax
    addq %rax, %rdx
    movl -4(%rbp) /* j */, %eax
    movslq %eax, %rax
    addq %rax, %rdx
    salq $2, %rdx
    movl -116(%rbp) /* k */, %eax
    movslq %eax, %rax
    addq %rdx, %rax
    movl -112(%rbp, %rax, 4), %r8d
    movl -8(%rbp) /* i */, %esi
    movl -4(%rbp) /* j */, %edx
    movl -116(%rbp) /* k */, %ecx
    leaq .LC1(%rip), %rdi
    movl $0, %eax
    call printf
.FOR_2_INNER_INCR:
    incl -116(%rbp) /* k */
.FOR_2_INNER_COMPARE:
    movl -116(%rbp) /* k */, %eax
    cmpl $4, %eax
    jl .FOR_2_INNER_ENTER

    movq	$10, %rdi
	call	putchar
.FOR_2_MID_INCR:
    incl -4(%rbp) /* j */
.FOR_2_MID_COMPARE:
    movl -4(%rbp) /* j */, %eax
    cmpl $3, %eax
    jl .FOR_2_MID_ENTER
.FOR_2_OUT_INCR:
    incl -8(%rbp) /* i */
.FOR_2_OUT_COMPARE:
    movl -8(%rbp) /* i */, %eax
    cmpl $2, %eax
    jl .FOR_2_OUT_ENTER

    movl $0, %eax
    movq %rbp, %rsp
    popq %rbp
    ret